1 Introduction

In order to properly design a map data visualization, it is important to understand some general visualization theory: variable data types. Variable data types determine the different visualization encodings that can be used for the data. We will introduce scatter map with a practical example.

2 Scatter maps

Scatter maps use discrete markers to represent the geographic location of the data and require latitude and longitude coordinates to be generated. When viewing the table, you will notice that it contains four pieces of geographic information: city, state, latitude, and longitude.

3 Case example Raw Data Table

3.1 Data Preparation

There are 2 raw data available on the Github website, including “POC” file and “PhillyCrimeSince2015” file. For “POC” file, we will select random sample of 500 elements in a subset of the data set. In addition, “PhillyCrimeSince2015” file will only select crime cases in 2023. Moreover, if the latitude and longitude of the subdataset are missing, the observation will be excluded.

# read final file
POC = read.csv("https://raw.githubusercontent.com/GUANTSERN-KUO/webcv/main/w07/POC.csv")
set.seed(123458)
#select random sample of 500 elements with NO replacement
kept_samp <- sample(1:nrow(POC), size = 500, replace = FALSE)

#select random sample of 500 rows from data frame
rand500_POC <- POC[kept_samp, ]
# write final data to csv file
write.csv(x = rand500_POC, file = "rand500_POC.csv", row.names = FALSE)
# read final file
Philly = read.csv("https://raw.githubusercontent.com/GUANTSERN-KUO/webcv/main/w07/PhillyCrimeSince2015.csv")
Philly$year <- year(as.POSIXct(Philly$date, format = "%m/%d/%Y %H:%M", tz = "EST") )


Philly2023 <- filter(Philly,year==2023)  # create 2023data

Philly2023 <- filter(Philly2023,!is.na(lat)) # remove missing obs



Philly2023$ageColor<-gsub("Fatal","orange",as.character(Philly2023$fatal))

Philly2023$ageColor<-gsub("Nonfatal","darkred",as.character(Philly2023$ageColor))
PhDT <- Philly2023 %>%
  dplyr::select(race, age,lng,lat,year)

POCDT <- rand500_POC %>%
  dplyr::select(STATE ,county,ADDRESS,ZIPnew,diesel,dist.to.poc,ycoord,xcoord)

3.2 Descriptive Study Purpose & Variables Relationship

The study primary focus on the distribution of diesel used in gas station. Secondary understanding of the Mean distance between a gas station and the Point of Compromised in PA. Finally, We want to understand crime map in PA.

The below is the sub-data table for “PhillyCrimeSince2015”. However, we will only use 5 variables and display data table as below.

  • lng : longitude
  • lat : latitude

The average age of offenders was 30.98, with the lowest age of offenders being 2.

summary(PhDT$age)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max.    NA's 
   2.00   21.00   29.00   30.98   37.00   87.00      23 

The below is the sub-data table for “POC”. However, we will only use 8 variables and display data table as below.

  • xcoord : longitude
  • ycoord : latitude
  • dist.to.poc : distance between a gas station and the nearest POC

The average distance was 17.6, with the lowest distance being 0.12 and maximum distance being 47.7.

summary(POCDT$dist.to.poc)
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.1292  5.6552 12.9125 17.6680 28.8643 47.7133 

3.3 Distribution of diesel used in gas station across U.S.

500 gas stations across U.S have been randomly selected from POC data. 294 gas stations provide Diesel service, that is 58.8 percent of selected gas stations. While 206 gas stations (41.2 percent) do not have Diesel service.

piedata <- filter(rand500_POC,!is.na(diesel))

piedataf = data.frame(cate =as.vector(unique(piedata$diesel)), 
                     freq = as.vector(table(piedata$diesel)))

## remove string X
piedataf$cate<-gsub("Y","Yes",as.character(piedataf$cate))
piedataf$cate<-gsub("N","No",as.character(piedataf$cate))


# define a color vector
colors <- c('rgb(211,94,96)', 'rgb(128,133,133)', 'rgb(144,103,167)')
# make a pie chart
plot_ly(piedataf, 
        labels = ~cate, 
        values = ~freq, 
        type = 'pie',
        textposition = 'inside',
        textinfo = 'label + percent',
        insidetextfont = list(color = '#FFFFFF'),
        #hoverinfo = 'text',
        marker = list(colors = colors,
                      line = list(color = '#FFFFFF', width = 1)),
                      #The 'pull' attribute can also be used to create space between the sectors
        showlegend = TRUE) %>% 
         layout(title = 'Distribution of diesel used in gas station',
                xaxis = list(showgrid = FALSE, zeroline = FALSE, 
                             showticklabels = FALSE),
                yaxis = list(showgrid = FALSE, zeroline = FALSE, 
                             showticklabels = FALSE),
                      ## margin of the plot
      margin = list(
              b = 50,
              l = 100,
              t = 120,
              r = 50
      ))

3.4 The diesel service of gas stations throughout the U.S

Looking at a the entire U.S. map, the supply of diesel fuel stations in each region is fairly normal regardless east region, west region, and central region. It is convenience for people to find diesel fuel stations as there are plenty of gas stations within each county and within short distance.

label.msg <- paste(paste("DIESEL:",rand500_POC$diesel),"\n")
                 



# making static leaflet map
map0 <- leaflet(rand500_POC) %>%
  addTiles() %>% 
  setView(lng=mean(rand500_POC$xcoord), lat=mean(rand500_POC$ycoord), zoom = 14) %>%
   addRectangles(
    lng1 = min(rand500_POC$xcoord), lat1 = min(rand500_POC$ycoord),
    lng2 = max(rand500_POC$xcoord), lat2 = max(rand500_POC$ycoord),
    #fillOpacity = 0.2,
    fillColor = "transparent" 
    ) %>%
  fitBounds(
    lng1 = min(rand500_POC$xcoord), lat1 = min(rand500_POC$ycoord),
    lng2 = max(rand500_POC$xcoord), lat2 = max(rand500_POC$ycoord) ) %>%
  addMarkers(~xcoord, ~ycoord, label = ~label.msg,
         
             popup = ~paste(label.msg, 
                            "<br>state:", STATE, 
                            "<br>county:", county, 
                            "<br>address", ADDRESS,
                            "<br>zip code", ZIPnew)
             
              )

title <- tags$div( HTML('<font color = "darkred" size =4><b>Do gas stations have diesel service throughout the U.S.?</b></font>')
)
 title2 <- tags$div( HTML('<font color = "red" size =0.5><b>500 randomly selected gas stations from the entire gas station dataset</b></font>')
)
###
map0 <- map0 %>%
     addControl(title, position = "topright")

map0 <- map0 %>%
     addControl(title2, position = "topright")

      
   

 map0

3.5 The Mean distance between a gas station and the Point of Compromised in PA 2023

Berks county has the highest mean distance (36.52) between a gas station and the Point of Compromised. Lehigh county has the lowest mean distance (7.27). The mean difference (29.25) between these two counties is pretty high.

PA_POC <- filter(rand500_POC,STATE == "PA")  # create 2015data


# Specify data frame
group_mean <- PA_POC %>%
    # Specify group indicator, column, function
    group_by(county) %>%
    # Calculate the mean of the "Frequency" column for each group
    summarise_at(vars(dist.to.poc),
                 list(Mean_Frequency = mean))
 
plot_ly(
    data = group_mean,
    x = ~county,  # Horizontal axis 
    y = ~Mean_Frequency,   # Vertical axis 
    color = ~factor(county),  # must be a numeric factor
    #text = ~Species,
  
     # Show the species in the hover text
     ## using the following hovertemplate() to add the information of the
     ## Two numerical variables to the hover text.
     ### Use the following hover template to display more information
    
     alpha  = 0.6,
   
     type = "scatter",
     mode = "markers",
     ## graphic size
     width = 700,
     height = 500

)%>%
    layout(  
      ### Title 
      title =list(text = "Mean distance between a gas station and the nearest POC in PA 2023", 
                  font = list(family = "Times New Roman",  # HTML font family  
                                size = 18,
                               color = "red")), 
      ### legend
      legend = list(title = list(text = 'county',
                                 font = list(family = "Courier New",
                                               size = 14,
                                              color = "green")),
                    bgcolor = "ivory",
                    bordercolor = "navy",
                    groupclick = "togglegroup",  # one of  "toggleitem" AND "togglegroup".
                    orientation = "v"  # Sets the orientation of the legend.
                    ),
      ## margin of the plot
      margin = list(
              b = 100,
              l = 100,
              t = 100,
              r = 50
      ),
      ## Background
      plot_bgcolor ='#f7f7f7', 
      ## Axes labels
             xaxis = list( 
                    title=list(text = 'County',
                               font = list(family = 'Arial')),
                    zerolinecolor = 'red', 
                    zerolinewidth = 2, 
                    gridcolor = 'white'), 
            yaxis = list( 
                    title=list(text = 'Mean distance',
                               font = list(family = 'Arial')),
                    zerolinecolor = 'purple', 
                    zerolinewidth = 2, 
                    gridcolor = 'white')

)

3.6 Crime Map in PA 2023

Below crime map is showing the offenders in PA state in year 2023. The amount of Non-fatal cases are higher than the amount of Fatal cases.

ageColor <- Philly2023$ageColor


label.msg <- paste(paste("Race:", Philly2023$race),    
                   paste("\n Age:",Philly2023$age),"\n")

#labels = cat(label.msg)
# making leaflet map
#labels = cat(label.msg)
# making leaflet map

# making leaflet map
 map <- leaflet(Philly2023) %>%
  addTiles() %>% 
  setView(lng=mean(Philly2023$lng), lat=mean(Philly2023$lat), zoom = 15) %>%
  #OpenStreetMap, Stamen, Esri and OpenWeatherMap.
  #addProviderTiles("Esri.WorldGrayCanvas") %>%
  addProviderTiles(providers$Esri.WorldGrayCanvas) %>%
  addCircleMarkers(
            ~lng, 
            ~lat,
            color = ageColor,
            radius = ~ (Philly2023$age/10),
            stroke = FALSE, 
            fillOpacity = 0.4,
            label = ~label.msg)  %>%
  addLegend(position = "bottomright", 
            colors = c("orange","darkred"),
            labels= c( "Fatal", "Nonfatal"),
            title= "Crime Category",
            opacity = 0.4) 
 
 
 
 
 title <- tags$div( HTML('<font color = "darkred" size =4><b>Pennsylvania crime map in 2023 </b></font>')
)
 title2 <- tags$div( HTML('<font color = "red" size =0.5><b>The point size is proportional to the age of the criminal </b></font>')
)
###
EnhancedMap <- map %>%
     addControl(title, position = "topright")

EnhancedMap <- EnhancedMap %>%
     addControl(title2, position = "topright")

      
   

 EnhancedMap
LS0tDQp0aXRsZTogIk1hcCBWaXN1bGF0aW9uIg0KYXV0aG9yOiAiR3VhbiBUc2VybiBLdW8iDQpkYXRlOiAiV2VzdCBDaGVzdGVyIFVuaXZlcnNpdHkiDQpvdXRwdXQ6DQogIGh0bWxfZG9jdW1lbnQ6IA0KICAgIHRvYzogeWVzDQogICAgdG9jX2Zsb2F0OiB5ZXMNCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcw0KICAgIHRvY19jb2xsYXBzZWQ6IHllcw0KICAgIGNvZGVfZm9sZGluZzogaGlkZQ0KICAgIGNvZGVfZG93bmxvYWQ6IHllcw0KICAgIHNtb290aF9zY3JvbGw6IHRydWUNCiAgICB0aGVtZTogbHVtZW4NCmVkaXRvcl9vcHRpb25zOg0KICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lDQotLS0NCg0KDQo8c3R5bGUgdHlwZT0idGV4dC9jc3MiPg0KDQovKiBUYWJsZSBvZiBjb250ZW50IC0gbmF2aWdhdGlvbiAqLw0KZGl2I1RPQyBsaSB7DQogICAgbGlzdC1zdHlsZTpub25lOw0KICAgIGJhY2tncm91bmQtY29sb3I6bGlnaHRncmF5Ow0KICAgIGJhY2tncm91bmQtaW1hZ2U6bm9uZTsNCiAgICBiYWNrZ3JvdW5kLXJlcGVhdDpub25lOw0KICAgIGJhY2tncm91bmQtcG9zaXRpb246MDsNCiAgICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgICBjb2xvcjogIzc4MGMwYzsNCn0NCg0KDQovKiBUaXRsZSBmb250cyAqLw0KaDEudGl0bGUgew0KICBmb250LXNpemU6IDI0cHg7DQogIGNvbG9yOiBkYXJrYmx1ZTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KICBmb250LWZhbWlseTogQXJpYWwsIEhlbHZldGljYSwgc2Fucy1zZXJpZjsNCiAgZm9udC12YXJpYW50LWNhcHM6IG5vcm1hbDsNCn0NCmg0LmF1dGhvciB7IA0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogbmF2eTsNCiAgdGV4dC1hbGlnbjogY2VudGVyOw0KfQ0KaDQuZGF0ZSB7IA0KICBmb250LXNpemU6IDE4cHg7DQogIGZvbnQtZmFtaWx5OiBBcmlhbCwgSGVsdmV0aWNhLCBzYW5zLXNlcmlmOw0KICBjb2xvcjogZGFya2JsdWU7DQogIHRleHQtYWxpZ246IGNlbnRlcjsNCn0NCg0KLyogU2VjdGlvbiBoZWFkZXJzICovDQpoMSB7DQogICAgZm9udC1zaXplOiAyMnB4Ow0KICAgIGZvbnQtZmFtaWx5OiAiVGltZXMgTmV3IFJvbWFuIiwgVGltZXMsIHNlcmlmOw0KICAgIGNvbG9yOiBkYXJrcmVkOw0KICAgIHRleHQtYWxpZ246IGxlZnQ7DQp9DQoNCmgyIHsNCiAgICBmb250LXNpemU6IDE4cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IG5hdnk7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDMgeyANCiAgICBmb250LXNpemU6IDE1cHg7DQogICAgZm9udC1mYW1pbHk6ICJUaW1lcyBOZXcgUm9tYW4iLCBUaW1lcywgc2VyaWY7DQogICAgY29sb3I6IGRhcmtyZWQ7DQogICAgdGV4dC1hbGlnbjogbGVmdDsNCn0NCg0KaDQgew0KICAgIGZvbnQtc2l6ZTogMThweDsNCiAgICBmb250LWZhbWlseTogIlRpbWVzIE5ldyBSb21hbiIsIFRpbWVzLCBzZXJpZjsNCiAgICBjb2xvcjogZGFya3JlZDsNCiAgICB0ZXh0LWFsaWduOiBsZWZ0Ow0KfQ0KDQovKiBEZWNvcmF0aW9uIG9mIGh5cGVybGlua3MgICovDQoNCi8qIHVudmlzaXRlZCBsaW5rICovDQphOmxpbmsgew0KICBjb2xvcjogZ3JlZW47DQp9DQoNCi8qIHZpc2l0ZWQgbGluayAqLw0KYTp2aXNpdGVkIHsNCiAgY29sb3I6IHB1cnBsZTsNCn0NCg0KLyogbW91c2Ugb3ZlciBsaW5rICovDQphOmhvdmVyIHsNCiAgY29sb3I6IHJlZDsNCn0NCg0KLyogc2VsZWN0ZWQgbGluayAqLw0KYTphY3RpdmUgew0KICBjb2xvcjogeWVsbG93Ow0KfQ0KPC9zdHlsZT4NCg0KYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9DQojIGNvZGUgY2h1bmsgc3BlY2lmaWVzIHdoZXRoZXIgdGhlIFIgY29kZSwgd2FybmluZ3MsIGFuZCBvdXRwdXQgDQojIHdpbGwgYmUgaW5jbHVkZWQgaW4gdGhlIG91dHB1dCBmaWxlcy4NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJ0aWR5dmVyc2UiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgidGlkeXZlcnNlIikNCn0NCg0KaWYgKCFyZXF1aXJlKCJkcGx5ciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiZHBseXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZHBseXIiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsdWJyaWRhdGUiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImx1YnJpZGF0ZSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJsdWJyaWRhdGUiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJncGxvdHMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdwbG90cyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJncGxvdHMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGV0IikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGV0IikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZsZXQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJtYXBzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJtYXBzIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoIm1hcHMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJodG1sdG9vbHMiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImh0bWx0b29scyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJodG1sdG9vbHMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJodG1sd2lkZ2V0cyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiaHRtbHdpZGdldHMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiaHRtbHdpZGdldHMiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJsZWFmbGVnZW5kIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJsZWFmbGVnZW5kIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImxlYWZsZWdlbmQiKQ0KfQ0KaWYgKCFyZXF1aXJlKCJnZW9qc29uaW8iKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImdlb2pzb25pbyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJnZW9qc29uaW8iKQ0KfQ0KDQoNCmlmICghcmVxdWlyZSgiZ2FwbWluZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImdhcG1pbmRlciIpDQogICBsaWJyYXJ5KGdhcG1pbmRlcikNCn0NCmlmICghcmVxdWlyZSgidGlkeXIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXIiKQ0KICAgbGlicmFyeSh0aWR5cikNCn0NCmlmICghcmVxdWlyZSgidGlkeXZlcnNlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInRpZHl2ZXJzZSIpDQogICBsaWJyYXJ5KHRpZHl2ZXJzZSkNCn0NCmlmICghcmVxdWlyZSgia25pdHIiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygia25pdHIiKQ0KICAgbGlicmFyeShrbml0cikNCn0NCmlmICghcmVxdWlyZSgiY293cGxvdCIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJjb3dwbG90IikNCiAgIGxpYnJhcnkoY293cGxvdCkNCn0NCmlmICghcmVxdWlyZSgibGF0ZXgyZXhwIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImxhdGV4MmV4cCIpDQogICBsaWJyYXJ5KGxhdGV4MmV4cCkNCn0NCmlmICghcmVxdWlyZSgicGxvdGx5IikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoInBsb3RseSIpDQogICBsaWJyYXJ5KHBsb3RseSkNCn0NCmlmICghcmVxdWlyZSgiZ2FwbWluZGVyIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImdhcG1pbmRlciIpDQogICBsaWJyYXJ5KGdhcG1pbmRlcikNCn0NCmlmICghcmVxdWlyZSgicG5nIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJwbmciKSAgICAgICAgICAgICAjIEluc3RhbGwgcG5nIHBhY2thZ2UNCiAgICBsaWJyYXJ5KCJwbmciKQ0KfQ0KaWYgKCFyZXF1aXJlKCJSQ3VybCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiUkN1cmwiKSAgICAgICAgICAgICAjIEluc3RhbGwgUkN1cmwgcGFja2FnZQ0KICAgIGxpYnJhcnkoIlJDdXJsIikNCn0NCmlmICghcmVxdWlyZSgiY29sb3VycGlja2VyIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJjb2xvdXJwaWNrZXIiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiY29sb3VycGlja2VyIikNCn0NCmlmICghcmVxdWlyZSgiZ2dhbmltYXRlIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnZ2FuaW1hdGUiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2dhbmltYXRlIikNCn0NCmlmICghcmVxdWlyZSgiZ2lmc2tpIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnaWZza2kiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ2lmc2tpIikNCn0NCmlmICghcmVxdWlyZSgibWFnaWNrIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJtYWdpY2siKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgibWFnaWNrIikNCn0NCmlmICghcmVxdWlyZSgiZ3JEZXZpY2VzIikpIHsNCiAgICBpbnN0YWxsLnBhY2thZ2VzKCJnckRldmljZXMiKSAgICAgICAgICAgICAgDQogICAgbGlicmFyeSgiZ3JEZXZpY2VzIikNCn0NCmlmICghcmVxdWlyZSgianBlZyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygianBlZyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJqcGVnIikNCn0NCmlmICghcmVxdWlyZSgiVkdBTSIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiVkdBTSIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJWR0FNIikNCn0NCmlmICghcmVxdWlyZSgiTUFTUyIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiTUFTUyIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJNQVNTIikNCn0NCmlmICghcmVxdWlyZSgibm5ldCIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygibm5ldCIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJubmV0IikNCn0NCmlmICghcmVxdWlyZSgiY2x1c3RlciIpKSB7DQogICAgaW5zdGFsbC5wYWNrYWdlcygiY2x1c3RlciIpICAgICAgICAgICAgICANCiAgICBsaWJyYXJ5KCJjbHVzdGVyIikNCn0NCmlmICghcmVxdWlyZSgiZHBseXIiKSkgew0KICAgIGluc3RhbGwucGFja2FnZXMoImRwbHlyIikgICAgICAgICAgICAgIA0KICAgIGxpYnJhcnkoImRwbHlyIikNCn0NCmlmICghcmVxdWlyZSgib2RiYyIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJvZGJjIikNCiAgIGxpYnJhcnkob2RiYykNCn0NCmlmICghcmVxdWlyZSgiREJJIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoIkRCSSIpDQogICBsaWJyYXJ5KERCSSkNCn0NCmlmICghcmVxdWlyZSgiUlNRTGl0ZSIpKSB7DQogICBpbnN0YWxsLnBhY2thZ2VzKCJSU1FMaXRlIikNCiAgIGxpYnJhcnkoUlNRTGl0ZSkNCn0NCg0KaWYgKCFyZXF1aXJlKCJ0aWR5dmVyc2UiKSkgew0KICAgaW5zdGFsbC5wYWNrYWdlcygidGlkeXZlcnNlIikNCiAgIGxpYnJhcnkodGlkeXZlcnNlKQ0KfQ0KaWYgKCFyZXF1aXJlKCJkYXRhLnRhYmxlIikpIHsNCiAgIGluc3RhbGwucGFja2FnZXMoImRhdGEudGFibGUiKQ0KICAgbGlicmFyeShkYXRhLnRhYmxlKQ0KfQ0KDQoNCiMga25pdHI6Om9wdHNfa25pdCRzZXQocm9vdC5kaXIgPSAiQzpcXFNUQTQ5MFxcdzA1IikNCmtuaXRyOjpvcHRzX2NodW5rJHNldChlY2hvID0gVFJVRSwgICAgICAgDQogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLCAgIA0KICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCA9IFRSVUUsICAgDQogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLA0KICAgICAgICAgICAgICAgICAgICAgIGNvbW1lbnQgPSBOQSkNCg0KZGIgPC0gZGJDb25uZWN0KFJTUUxpdGU6OlNRTGl0ZSgpLCBkYm5hbWUgPSAic3FsLnNxbGl0ZSIpDQprbml0cjo6b3B0c19jaHVuayRzZXQoY29ubmVjdGlvbiA9ICJkYiIpDQoNCg0KYGBgDQoNCg0KIyBJbnRyb2R1Y3Rpb24gDQoNCkluIG9yZGVyIHRvIHByb3Blcmx5IGRlc2lnbiBhIG1hcCBkYXRhIHZpc3VhbGl6YXRpb24sIGl0IGlzIGltcG9ydGFudCB0byB1bmRlcnN0YW5kIHNvbWUgZ2VuZXJhbCB2aXN1YWxpemF0aW9uIHRoZW9yeTogdmFyaWFibGUgZGF0YSB0eXBlcy4gVmFyaWFibGUgZGF0YSB0eXBlcyBkZXRlcm1pbmUgdGhlIGRpZmZlcmVudCB2aXN1YWxpemF0aW9uIGVuY29kaW5ncyB0aGF0IGNhbiBiZSB1c2VkIGZvciB0aGUgZGF0YS4gV2Ugd2lsbCBpbnRyb2R1Y2Ugc2NhdHRlciBtYXAgd2l0aCBhIHByYWN0aWNhbCBleGFtcGxlLg0KDQoNCg0KIyBTY2F0dGVyIG1hcHMNCg0KU2NhdHRlciBtYXBzIHVzZSBkaXNjcmV0ZSBtYXJrZXJzIHRvIHJlcHJlc2VudCB0aGUgZ2VvZ3JhcGhpYyBsb2NhdGlvbiBvZiB0aGUgZGF0YSBhbmQgcmVxdWlyZSBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIGNvb3JkaW5hdGVzIHRvIGJlIGdlbmVyYXRlZC4gV2hlbiB2aWV3aW5nIHRoZSB0YWJsZSwgeW91IHdpbGwgbm90aWNlIHRoYXQgaXQgY29udGFpbnMgZm91ciBwaWVjZXMgb2YgZ2VvZ3JhcGhpYyBpbmZvcm1hdGlvbjogY2l0eSwgc3RhdGUsIGxhdGl0dWRlLCBhbmQgbG9uZ2l0dWRlLg0KDQoNCmBgYHtyICxlY2hvID0gRkFMU0V9DQprbml0cjo6IGluY2x1ZGVfZ3JhcGhpY3MoInBpYy5naWYiKQ0KYGBgDQoNCg0KIyBDYXNlIGV4YW1wbGUgUmF3IERhdGEgVGFibGUgDQoNCiMjIERhdGEgUHJlcGFyYXRpb24NCg0KDQpUaGVyZSBhcmUgMiByYXcgZGF0YSBhdmFpbGFibGUgb24gdGhlIEdpdGh1YiB3ZWJzaXRlLCBpbmNsdWRpbmcgIlBPQyIgZmlsZSBhbmQgIlBoaWxseUNyaW1lU2luY2UyMDE1IiBmaWxlLiBGb3IgIlBPQyIgZmlsZSwgd2UgIHdpbGwgc2VsZWN0IHJhbmRvbSBzYW1wbGUgb2YgNTAwIGVsZW1lbnRzIGluIGEgc3Vic2V0IG9mIHRoZSBkYXRhIHNldC4gSW4gYWRkaXRpb24sICJQaGlsbHlDcmltZVNpbmNlMjAxNSIgZmlsZSB3aWxsIG9ubHkgc2VsZWN0IGNyaW1lIGNhc2VzIGluIDIwMjMuIE1vcmVvdmVyLCBpZiB0aGUgbGF0aXR1ZGUgYW5kIGxvbmdpdHVkZSBvZiB0aGUgc3ViZGF0YXNldCBhcmUgbWlzc2luZywgdGhlIG9ic2VydmF0aW9uIHdpbGwgYmUgZXhjbHVkZWQuDQoNCg0KDQoNCmBgYHtyfQ0KDQojIHJlYWQgZmluYWwgZmlsZQ0KUE9DID0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVUFOVFNFUk4tS1VPL3dlYmN2L21haW4vdzA3L1BPQy5jc3YiKQ0KDQpgYGANCg0KYGBge3J9DQpzZXQuc2VlZCgxMjM0NTgpDQojc2VsZWN0IHJhbmRvbSBzYW1wbGUgb2YgNTAwIGVsZW1lbnRzIHdpdGggTk8gcmVwbGFjZW1lbnQNCmtlcHRfc2FtcCA8LSBzYW1wbGUoMTpucm93KFBPQyksIHNpemUgPSA1MDAsIHJlcGxhY2UgPSBGQUxTRSkNCg0KI3NlbGVjdCByYW5kb20gc2FtcGxlIG9mIDUwMCByb3dzIGZyb20gZGF0YSBmcmFtZQ0KcmFuZDUwMF9QT0MgPC0gUE9DW2tlcHRfc2FtcCwgXQ0KDQoNCmBgYA0KDQoNCmBgYHtyfQ0KIyB3cml0ZSBmaW5hbCBkYXRhIHRvIGNzdiBmaWxlDQp3cml0ZS5jc3YoeCA9IHJhbmQ1MDBfUE9DLCBmaWxlID0gInJhbmQ1MDBfUE9DLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQ0KYGBgDQoNCg0KYGBge3J9DQojIHJlYWQgZmluYWwgZmlsZQ0KUGhpbGx5ID0gcmVhZC5jc3YoImh0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9HVUFOVFNFUk4tS1VPL3dlYmN2L21haW4vdzA3L1BoaWxseUNyaW1lU2luY2UyMDE1LmNzdiIpDQpQaGlsbHkkeWVhciA8LSB5ZWFyKGFzLlBPU0lYY3QoUGhpbGx5JGRhdGUsIGZvcm1hdCA9ICIlbS8lZC8lWSAlSDolTSIsIHR6ID0gIkVTVCIpICkNCg0KDQpQaGlsbHkyMDIzIDwtIGZpbHRlcihQaGlsbHkseWVhcj09MjAyMykgICMgY3JlYXRlIDIwMjNkYXRhDQoNClBoaWxseTIwMjMgPC0gZmlsdGVyKFBoaWxseTIwMjMsIWlzLm5hKGxhdCkpICMgcmVtb3ZlIG1pc3Npbmcgb2JzDQoNCg0KDQpQaGlsbHkyMDIzJGFnZUNvbG9yPC1nc3ViKCJGYXRhbCIsIm9yYW5nZSIsYXMuY2hhcmFjdGVyKFBoaWxseTIwMjMkZmF0YWwpKQ0KDQpQaGlsbHkyMDIzJGFnZUNvbG9yPC1nc3ViKCJOb25mYXRhbCIsImRhcmtyZWQiLGFzLmNoYXJhY3RlcihQaGlsbHkyMDIzJGFnZUNvbG9yKSkNCg0KYGBgDQoNCmBgYHtyfQ0KDQpQaERUIDwtIFBoaWxseTIwMjMgJT4lDQogIGRwbHlyOjpzZWxlY3QocmFjZSwgYWdlLGxuZyxsYXQseWVhcikNCg0KUE9DRFQgPC0gcmFuZDUwMF9QT0MgJT4lDQogIGRwbHlyOjpzZWxlY3QoU1RBVEUgLGNvdW50eSxBRERSRVNTLFpJUG5ldyxkaWVzZWwsZGlzdC50by5wb2MseWNvb3JkLHhjb29yZCkNCmBgYA0KDQoNCiMjIERlc2NyaXB0aXZlIFN0dWR5IFB1cnBvc2UgJiBWYXJpYWJsZXMgUmVsYXRpb25zaGlwIA0KDQpUaGUgc3R1ZHkgcHJpbWFyeSBmb2N1cyBvbiB0aGUgZGlzdHJpYnV0aW9uIG9mIGRpZXNlbCB1c2VkIGluIGdhcyBzdGF0aW9uLiBTZWNvbmRhcnkgdW5kZXJzdGFuZGluZyBvZiB0aGUgTWVhbiBkaXN0YW5jZSBiZXR3ZWVuIGEgZ2FzIHN0YXRpb24gYW5kIHRoZSBQb2ludCBvZiBDb21wcm9taXNlZCBpbiBQQS4gRmluYWxseSwgV2Ugd2FudCB0byB1bmRlcnN0YW5kIGNyaW1lIG1hcCBpbiBQQS4NCg0KDQoNCg0KVGhlIGJlbG93IGlzIHRoZSBzdWItZGF0YSB0YWJsZSBmb3IgIlBoaWxseUNyaW1lU2luY2UyMDE1Ii4gSG93ZXZlciwgd2Ugd2lsbCBvbmx5IHVzZSA1IHZhcmlhYmxlcyBhbmQgZGlzcGxheSBkYXRhIHRhYmxlIGFzIGJlbG93Lg0KDQoNCi0gbG5nIDogbG9uZ2l0dWRlDQotIGxhdCA6IGxhdGl0dWRlDQoNCg0KDQpgYGB7ciBldmFsPXJlcXVpcmVOYW1lc3BhY2UoIkRUIiwgcXVpZXRseT1UUlVFKSwgZWNobz1GQUxTRX0NCkRUOjpkYXRhdGFibGUoKFBoRFQpLCBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA2ICkgICkNCg0KYGBgDQpUaGUgYXZlcmFnZSBhZ2Ugb2Ygb2ZmZW5kZXJzIHdhcyAzMC45OCwgd2l0aCB0aGUgbG93ZXN0IGFnZSBvZiBvZmZlbmRlcnMgYmVpbmcgMi4NCg0KYGBge3J9DQpzdW1tYXJ5KFBoRFQkYWdlKQ0KDQpgYGANCg0KDQoNCg0KDQoNCg0KDQpUaGUgYmVsb3cgaXMgdGhlIHN1Yi1kYXRhIHRhYmxlIGZvciAiUE9DIi4gSG93ZXZlciwgd2Ugd2lsbCBvbmx5IHVzZSA4IHZhcmlhYmxlcyBhbmQgZGlzcGxheSBkYXRhIHRhYmxlIGFzIGJlbG93Lg0KDQoNCi0geGNvb3JkIDogbG9uZ2l0dWRlDQotIHljb29yZCA6IGxhdGl0dWRlDQotIGRpc3QudG8ucG9jIDogZGlzdGFuY2UgYmV0d2VlbiBhIGdhcyBzdGF0aW9uIGFuZCB0aGUgbmVhcmVzdCBQT0MNCmBgYHtyIGV2YWw9cmVxdWlyZU5hbWVzcGFjZSgiRFQiLCBxdWlldGx5PVRSVUUpLCBlY2hvPUZBTFNFfQ0KRFQ6OmRhdGF0YWJsZSgoUE9DRFQpLCBmaWxsQ29udGFpbmVyID0gRkFMU0UsIG9wdGlvbnMgPSBsaXN0KHBhZ2VMZW5ndGggPSA2ICkgICkNCg0KYGBgDQoNClRoZSBhdmVyYWdlIGRpc3RhbmNlIHdhcyAxNy42LCB3aXRoIHRoZSBsb3dlc3QgZGlzdGFuY2UgYmVpbmcgMC4xMiBhbmQgbWF4aW11bSBkaXN0YW5jZSBiZWluZyA0Ny43Lg0KDQoNCmBgYHtyfQ0Kc3VtbWFyeShQT0NEVCRkaXN0LnRvLnBvYykNCg0KYGBgDQoNCg0KDQojIyAgIERpc3RyaWJ1dGlvbiBvZiBkaWVzZWwgdXNlZCBpbiBnYXMgc3RhdGlvbiBhY3Jvc3MgVS5TLg0KDQo1MDAgZ2FzIHN0YXRpb25zIGFjcm9zcyBVLlMgaGF2ZSBiZWVuIHJhbmRvbWx5IHNlbGVjdGVkIGZyb20gUE9DIGRhdGEuIDI5NCBnYXMgc3RhdGlvbnMgcHJvdmlkZSBEaWVzZWwgc2VydmljZSwgdGhhdCBpcyA1OC44IHBlcmNlbnQgb2Ygc2VsZWN0ZWQgZ2FzIHN0YXRpb25zLiBXaGlsZSAyMDYgZ2FzIHN0YXRpb25zICg0MS4yIHBlcmNlbnQpIGRvIG5vdCBoYXZlIERpZXNlbCBzZXJ2aWNlLg0KDQoNCmBgYHtyfQ0KcGllZGF0YSA8LSBmaWx0ZXIocmFuZDUwMF9QT0MsIWlzLm5hKGRpZXNlbCkpDQoNCnBpZWRhdGFmID0gZGF0YS5mcmFtZShjYXRlID1hcy52ZWN0b3IodW5pcXVlKHBpZWRhdGEkZGllc2VsKSksIA0KICAgICAgICAgICAgICAgICAgICAgZnJlcSA9IGFzLnZlY3Rvcih0YWJsZShwaWVkYXRhJGRpZXNlbCkpKQ0KDQojIyByZW1vdmUgc3RyaW5nIFgNCnBpZWRhdGFmJGNhdGU8LWdzdWIoIlkiLCJZZXMiLGFzLmNoYXJhY3RlcihwaWVkYXRhZiRjYXRlKSkNCnBpZWRhdGFmJGNhdGU8LWdzdWIoIk4iLCJObyIsYXMuY2hhcmFjdGVyKHBpZWRhdGFmJGNhdGUpKQ0KDQoNCiMgZGVmaW5lIGEgY29sb3IgdmVjdG9yDQpjb2xvcnMgPC0gYygncmdiKDIxMSw5NCw5NiknLCAncmdiKDEyOCwxMzMsMTMzKScsICdyZ2IoMTQ0LDEwMywxNjcpJykNCiMgbWFrZSBhIHBpZSBjaGFydA0KcGxvdF9seShwaWVkYXRhZiwgDQogICAgICAgIGxhYmVscyA9IH5jYXRlLCANCiAgICAgICAgdmFsdWVzID0gfmZyZXEsIA0KICAgICAgICB0eXBlID0gJ3BpZScsDQogICAgICAgIHRleHRwb3NpdGlvbiA9ICdpbnNpZGUnLA0KICAgICAgICB0ZXh0aW5mbyA9ICdsYWJlbCArIHBlcmNlbnQnLA0KICAgICAgICBpbnNpZGV0ZXh0Zm9udCA9IGxpc3QoY29sb3IgPSAnI0ZGRkZGRicpLA0KICAgICAgICAjaG92ZXJpbmZvID0gJ3RleHQnLA0KICAgICAgICBtYXJrZXIgPSBsaXN0KGNvbG9ycyA9IGNvbG9ycywNCiAgICAgICAgICAgICAgICAgICAgICBsaW5lID0gbGlzdChjb2xvciA9ICcjRkZGRkZGJywgd2lkdGggPSAxKSksDQogICAgICAgICAgICAgICAgICAgICAgI1RoZSAncHVsbCcgYXR0cmlidXRlIGNhbiBhbHNvIGJlIHVzZWQgdG8gY3JlYXRlIHNwYWNlIGJldHdlZW4gdGhlIHNlY3RvcnMNCiAgICAgICAgc2hvd2xlZ2VuZCA9IFRSVUUpICU+JSANCiAgICAgICAgIGxheW91dCh0aXRsZSA9ICdEaXN0cmlidXRpb24gb2YgZGllc2VsIHVzZWQgaW4gZ2FzIHN0YXRpb24nLA0KICAgICAgICAgICAgICAgIHhheGlzID0gbGlzdChzaG93Z3JpZCA9IEZBTFNFLCB6ZXJvbGluZSA9IEZBTFNFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hvd3RpY2tsYWJlbHMgPSBGQUxTRSksDQogICAgICAgICAgICAgICAgeWF4aXMgPSBsaXN0KHNob3dncmlkID0gRkFMU0UsIHplcm9saW5lID0gRkFMU0UsIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaG93dGlja2xhYmVscyA9IEZBTFNFKSwNCiAgICAgICAgICAgICAgICAgICAgICAjIyBtYXJnaW4gb2YgdGhlIHBsb3QNCiAgICAgIG1hcmdpbiA9IGxpc3QoDQogICAgICAgICAgICAgIGIgPSA1MCwNCiAgICAgICAgICAgICAgbCA9IDEwMCwNCiAgICAgICAgICAgICAgdCA9IDEyMCwNCiAgICAgICAgICAgICAgciA9IDUwDQogICAgICApKQ0KDQoNCmBgYCANCg0KDQojIyAgIFRoZSBkaWVzZWwgc2VydmljZSBvZiBnYXMgc3RhdGlvbnMgdGhyb3VnaG91dCB0aGUgVS5TDQoNCkxvb2tpbmcgYXQgYSB0aGUgZW50aXJlIFUuUy4gbWFwLCB0aGUgc3VwcGx5IG9mIGRpZXNlbCBmdWVsIHN0YXRpb25zIGluIGVhY2ggcmVnaW9uIGlzIGZhaXJseSBub3JtYWwgcmVnYXJkbGVzcyBlYXN0IHJlZ2lvbiwgd2VzdCByZWdpb24sIGFuZCBjZW50cmFsIHJlZ2lvbi4gSXQgaXMgY29udmVuaWVuY2UgZm9yIHBlb3BsZSB0byBmaW5kIGRpZXNlbCBmdWVsIHN0YXRpb25zIGFzIHRoZXJlIGFyZSBwbGVudHkgb2YgZ2FzIHN0YXRpb25zIHdpdGhpbiBlYWNoIGNvdW50eSBhbmQgd2l0aGluIHNob3J0IGRpc3RhbmNlLg0KDQoNCmBgYHtyfQ0KDQoNCmxhYmVsLm1zZyA8LSBwYXN0ZShwYXN0ZSgiRElFU0VMOiIscmFuZDUwMF9QT0MkZGllc2VsKSwiXG4iKQ0KICAgICAgICAgICAgICAgICANCg0KDQoNCiMgbWFraW5nIHN0YXRpYyBsZWFmbGV0IG1hcA0KbWFwMCA8LSBsZWFmbGV0KHJhbmQ1MDBfUE9DKSAlPiUNCiAgYWRkVGlsZXMoKSAlPiUgDQogIHNldFZpZXcobG5nPW1lYW4ocmFuZDUwMF9QT0MkeGNvb3JkKSwgbGF0PW1lYW4ocmFuZDUwMF9QT0MkeWNvb3JkKSwgem9vbSA9IDE0KSAlPiUNCiAgIGFkZFJlY3RhbmdsZXMoDQogICAgbG5nMSA9IG1pbihyYW5kNTAwX1BPQyR4Y29vcmQpLCBsYXQxID0gbWluKHJhbmQ1MDBfUE9DJHljb29yZCksDQogICAgbG5nMiA9IG1heChyYW5kNTAwX1BPQyR4Y29vcmQpLCBsYXQyID0gbWF4KHJhbmQ1MDBfUE9DJHljb29yZCksDQogICAgI2ZpbGxPcGFjaXR5ID0gMC4yLA0KICAgIGZpbGxDb2xvciA9ICJ0cmFuc3BhcmVudCIgDQogICAgKSAlPiUNCiAgZml0Qm91bmRzKA0KICAgIGxuZzEgPSBtaW4ocmFuZDUwMF9QT0MkeGNvb3JkKSwgbGF0MSA9IG1pbihyYW5kNTAwX1BPQyR5Y29vcmQpLA0KICAgIGxuZzIgPSBtYXgocmFuZDUwMF9QT0MkeGNvb3JkKSwgbGF0MiA9IG1heChyYW5kNTAwX1BPQyR5Y29vcmQpICkgJT4lDQogIGFkZE1hcmtlcnMofnhjb29yZCwgfnljb29yZCwgbGFiZWwgPSB+bGFiZWwubXNnLA0KICAgICAgICAgDQogICAgICAgICAgICAgcG9wdXAgPSB+cGFzdGUobGFiZWwubXNnLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPnN0YXRlOiIsIFNUQVRFLCANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAiPGJyPmNvdW50eToiLCBjb3VudHksIA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICI8YnI+YWRkcmVzcyIsIEFERFJFU1MsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgIjxicj56aXAgY29kZSIsIFpJUG5ldykNCiAgICAgICAgICAgICANCiAgICAgICAgICAgICAgKQ0KDQp0aXRsZSA8LSB0YWdzJGRpdiggSFRNTCgnPGZvbnQgY29sb3IgPSAiZGFya3JlZCIgc2l6ZSA9ND48Yj5EbyBnYXMgc3RhdGlvbnMgaGF2ZSBkaWVzZWwgc2VydmljZSB0aHJvdWdob3V0IHRoZSBVLlMuPzwvYj48L2ZvbnQ+JykNCikNCiB0aXRsZTIgPC0gdGFncyRkaXYoIEhUTUwoJzxmb250IGNvbG9yID0gInJlZCIgc2l6ZSA9MC41PjxiPjUwMCByYW5kb21seSBzZWxlY3RlZCBnYXMgc3RhdGlvbnMgZnJvbSB0aGUgZW50aXJlIGdhcyBzdGF0aW9uIGRhdGFzZXQ8L2I+PC9mb250PicpDQopDQojIyMNCm1hcDAgPC0gbWFwMCAlPiUNCiAgICAgYWRkQ29udHJvbCh0aXRsZSwgcG9zaXRpb24gPSAidG9wcmlnaHQiKQ0KDQptYXAwIDwtIG1hcDAgJT4lDQogICAgIGFkZENvbnRyb2wodGl0bGUyLCBwb3NpdGlvbiA9ICJ0b3ByaWdodCIpDQoNCiAgICAgIA0KICAgDQoNCiBtYXAwDQoNCmBgYA0KDQojIyAgIFRoZSBNZWFuIGRpc3RhbmNlIGJldHdlZW4gYSBnYXMgc3RhdGlvbiBhbmQgdGhlIFBvaW50IG9mIENvbXByb21pc2VkIGluIFBBIDIwMjMNCg0KQmVya3MgY291bnR5IGhhcyB0aGUgaGlnaGVzdCBtZWFuIGRpc3RhbmNlICgzNi41MikgYmV0d2VlbiBhIGdhcyBzdGF0aW9uIGFuZCB0aGUgUG9pbnQgb2YgQ29tcHJvbWlzZWQuIExlaGlnaCBjb3VudHkgaGFzIHRoZSBsb3dlc3QgbWVhbiBkaXN0YW5jZSAoNy4yNykuIFRoZSBtZWFuIGRpZmZlcmVuY2UgKDI5LjI1KSBiZXR3ZWVuIHRoZXNlIHR3byBjb3VudGllcyBpcyBwcmV0dHkgaGlnaC4NCg0KYGBge3J9DQoNClBBX1BPQyA8LSBmaWx0ZXIocmFuZDUwMF9QT0MsU1RBVEUgPT0gIlBBIikgICMgY3JlYXRlIDIwMTVkYXRhDQoNCg0KIyBTcGVjaWZ5IGRhdGEgZnJhbWUNCmdyb3VwX21lYW4gPC0gUEFfUE9DICU+JQ0KICAgICMgU3BlY2lmeSBncm91cCBpbmRpY2F0b3IsIGNvbHVtbiwgZnVuY3Rpb24NCiAgICBncm91cF9ieShjb3VudHkpICU+JQ0KICAgICMgQ2FsY3VsYXRlIHRoZSBtZWFuIG9mIHRoZSAiRnJlcXVlbmN5IiBjb2x1bW4gZm9yIGVhY2ggZ3JvdXANCiAgICBzdW1tYXJpc2VfYXQodmFycyhkaXN0LnRvLnBvYyksDQogICAgICAgICAgICAgICAgIGxpc3QoTWVhbl9GcmVxdWVuY3kgPSBtZWFuKSkNCiANCnBsb3RfbHkoDQogICAgZGF0YSA9IGdyb3VwX21lYW4sDQogICAgeCA9IH5jb3VudHksICAjIEhvcml6b250YWwgYXhpcyANCiAgICB5ID0gfk1lYW5fRnJlcXVlbmN5LCAgICMgVmVydGljYWwgYXhpcyANCiAgICBjb2xvciA9IH5mYWN0b3IoY291bnR5KSwgICMgbXVzdCBiZSBhIG51bWVyaWMgZmFjdG9yDQogICAgI3RleHQgPSB+U3BlY2llcywNCiAgDQogICAgICMgU2hvdyB0aGUgc3BlY2llcyBpbiB0aGUgaG92ZXIgdGV4dA0KICAgICAjIyB1c2luZyB0aGUgZm9sbG93aW5nIGhvdmVydGVtcGxhdGUoKSB0byBhZGQgdGhlIGluZm9ybWF0aW9uIG9mIHRoZQ0KICAgICAjIyBUd28gbnVtZXJpY2FsIHZhcmlhYmxlcyB0byB0aGUgaG92ZXIgdGV4dC4NCiAgICAgIyMjIFVzZSB0aGUgZm9sbG93aW5nIGhvdmVyIHRlbXBsYXRlIHRvIGRpc3BsYXkgbW9yZSBpbmZvcm1hdGlvbg0KICAgIA0KICAgICBhbHBoYSAgPSAwLjYsDQogICANCiAgICAgdHlwZSA9ICJzY2F0dGVyIiwNCiAgICAgbW9kZSA9ICJtYXJrZXJzIiwNCiAgICAgIyMgZ3JhcGhpYyBzaXplDQogICAgIHdpZHRoID0gNzAwLA0KICAgICBoZWlnaHQgPSA1MDANCg0KKSU+JQ0KICAgIGxheW91dCggIA0KICAgICAgIyMjIFRpdGxlIA0KICAgICAgdGl0bGUgPWxpc3QodGV4dCA9ICJNZWFuIGRpc3RhbmNlIGJldHdlZW4gYSBnYXMgc3RhdGlvbiBhbmQgdGhlIG5lYXJlc3QgUE9DIGluIFBBIDIwMjMiLCANCiAgICAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICJUaW1lcyBOZXcgUm9tYW4iLCAgIyBIVE1MIGZvbnQgZmFtaWx5ICANCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE4LA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gInJlZCIpKSwgDQogICAgICAjIyMgbGVnZW5kDQogICAgICBsZWdlbmQgPSBsaXN0KHRpdGxlID0gbGlzdCh0ZXh0ID0gJ2NvdW50eScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb250ID0gbGlzdChmYW1pbHkgPSAiQ291cmllciBOZXciLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gMTQsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JlZW4iKSksDQogICAgICAgICAgICAgICAgICAgIGJnY29sb3IgPSAiaXZvcnkiLA0KICAgICAgICAgICAgICAgICAgICBib3JkZXJjb2xvciA9ICJuYXZ5IiwNCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBjbGljayA9ICJ0b2dnbGVncm91cCIsICAjIG9uZSBvZiAgInRvZ2dsZWl0ZW0iIEFORCAidG9nZ2xlZ3JvdXAiLg0KICAgICAgICAgICAgICAgICAgICBvcmllbnRhdGlvbiA9ICJ2IiAgIyBTZXRzIHRoZSBvcmllbnRhdGlvbiBvZiB0aGUgbGVnZW5kLg0KICAgICAgICAgICAgICAgICAgICApLA0KICAgICAgIyMgbWFyZ2luIG9mIHRoZSBwbG90DQogICAgICBtYXJnaW4gPSBsaXN0KA0KICAgICAgICAgICAgICBiID0gMTAwLA0KICAgICAgICAgICAgICBsID0gMTAwLA0KICAgICAgICAgICAgICB0ID0gMTAwLA0KICAgICAgICAgICAgICByID0gNTANCiAgICAgICksDQogICAgICAjIyBCYWNrZ3JvdW5kDQogICAgICBwbG90X2JnY29sb3IgPScjZjdmN2Y3JywgDQogICAgICAjIyBBeGVzIGxhYmVscw0KICAgICAgICAgICAgIHhheGlzID0gbGlzdCggDQogICAgICAgICAgICAgICAgICAgIHRpdGxlPWxpc3QodGV4dCA9ICdDb3VudHknLA0KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvbnQgPSBsaXN0KGZhbWlseSA9ICdBcmlhbCcpKSwNCiAgICAgICAgICAgICAgICAgICAgemVyb2xpbmVjb2xvciA9ICdyZWQnLCANCiAgICAgICAgICAgICAgICAgICAgemVyb2xpbmV3aWR0aCA9IDIsIA0KICAgICAgICAgICAgICAgICAgICBncmlkY29sb3IgPSAnd2hpdGUnKSwgDQogICAgICAgICAgICB5YXhpcyA9IGxpc3QoIA0KICAgICAgICAgICAgICAgICAgICB0aXRsZT1saXN0KHRleHQgPSAnTWVhbiBkaXN0YW5jZScsDQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9udCA9IGxpc3QoZmFtaWx5ID0gJ0FyaWFsJykpLA0KICAgICAgICAgICAgICAgICAgICB6ZXJvbGluZWNvbG9yID0gJ3B1cnBsZScsIA0KICAgICAgICAgICAgICAgICAgICB6ZXJvbGluZXdpZHRoID0gMiwgDQogICAgICAgICAgICAgICAgICAgIGdyaWRjb2xvciA9ICd3aGl0ZScpDQoNCikNCg0KYGBgDQoNCg0KDQoNCg0KDQojIyAgIENyaW1lIE1hcCBpbiBQQSAyMDIzDQoNCkJlbG93IGNyaW1lIG1hcCBpcyBzaG93aW5nIHRoZSBvZmZlbmRlcnMgaW4gUEEgc3RhdGUgaW4geWVhciAyMDIzLiBUaGUgYW1vdW50IG9mIE5vbi1mYXRhbCBjYXNlcyBhcmUgaGlnaGVyIHRoYW4gdGhlIGFtb3VudCBvZiBGYXRhbCBjYXNlcy4gDQoNCg0KYGBge3J9DQoNCmFnZUNvbG9yIDwtIFBoaWxseTIwMjMkYWdlQ29sb3INCg0KDQpsYWJlbC5tc2cgPC0gcGFzdGUocGFzdGUoIlJhY2U6IiwgUGhpbGx5MjAyMyRyYWNlKSwgICAgDQogICAgICAgICAgICAgICAgICAgcGFzdGUoIlxuIEFnZToiLFBoaWxseTIwMjMkYWdlKSwiXG4iKQ0KDQojbGFiZWxzID0gY2F0KGxhYmVsLm1zZykNCiMgbWFraW5nIGxlYWZsZXQgbWFwDQojbGFiZWxzID0gY2F0KGxhYmVsLm1zZykNCiMgbWFraW5nIGxlYWZsZXQgbWFwDQoNCiMgbWFraW5nIGxlYWZsZXQgbWFwDQogbWFwIDwtIGxlYWZsZXQoUGhpbGx5MjAyMykgJT4lDQogIGFkZFRpbGVzKCkgJT4lIA0KICBzZXRWaWV3KGxuZz1tZWFuKFBoaWxseTIwMjMkbG5nKSwgbGF0PW1lYW4oUGhpbGx5MjAyMyRsYXQpLCB6b29tID0gMTUpICU+JQ0KICAjT3BlblN0cmVldE1hcCwgU3RhbWVuLCBFc3JpIGFuZCBPcGVuV2VhdGhlck1hcC4NCiAgI2FkZFByb3ZpZGVyVGlsZXMoIkVzcmkuV29ybGRHcmF5Q2FudmFzIikgJT4lDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJEVzcmkuV29ybGRHcmF5Q2FudmFzKSAlPiUNCiAgYWRkQ2lyY2xlTWFya2VycygNCiAgICAgICAgICAgIH5sbmcsIA0KICAgICAgICAgICAgfmxhdCwNCiAgICAgICAgICAgIGNvbG9yID0gYWdlQ29sb3IsDQogICAgICAgICAgICByYWRpdXMgPSB+IChQaGlsbHkyMDIzJGFnZS8xMCksDQogICAgICAgICAgICBzdHJva2UgPSBGQUxTRSwgDQogICAgICAgICAgICBmaWxsT3BhY2l0eSA9IDAuNCwNCiAgICAgICAgICAgIGxhYmVsID0gfmxhYmVsLm1zZykgICU+JQ0KICBhZGRMZWdlbmQocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiLCANCiAgICAgICAgICAgIGNvbG9ycyA9IGMoIm9yYW5nZSIsImRhcmtyZWQiKSwNCiAgICAgICAgICAgIGxhYmVscz0gYyggIkZhdGFsIiwgIk5vbmZhdGFsIiksDQogICAgICAgICAgICB0aXRsZT0gIkNyaW1lIENhdGVnb3J5IiwNCiAgICAgICAgICAgIG9wYWNpdHkgPSAwLjQpIA0KIA0KIA0KIA0KIA0KIHRpdGxlIDwtIHRhZ3MkZGl2KCBIVE1MKCc8Zm9udCBjb2xvciA9ICJkYXJrcmVkIiBzaXplID00PjxiPlBlbm5zeWx2YW5pYSBjcmltZSBtYXAgaW4gMjAyMyA8L2I+PC9mb250PicpDQopDQogdGl0bGUyIDwtIHRhZ3MkZGl2KCBIVE1MKCc8Zm9udCBjb2xvciA9ICJyZWQiIHNpemUgPTAuNT48Yj5UaGUgcG9pbnQgc2l6ZSBpcyBwcm9wb3J0aW9uYWwgdG8gdGhlIGFnZSBvZiB0aGUgY3JpbWluYWwgPC9iPjwvZm9udD4nKQ0KKQ0KIyMjDQpFbmhhbmNlZE1hcCA8LSBtYXAgJT4lDQogICAgIGFkZENvbnRyb2wodGl0bGUsIHBvc2l0aW9uID0gInRvcHJpZ2h0IikNCg0KRW5oYW5jZWRNYXAgPC0gRW5oYW5jZWRNYXAgJT4lDQogICAgIGFkZENvbnRyb2wodGl0bGUyLCBwb3NpdGlvbiA9ICJ0b3ByaWdodCIpDQoNCiAgICAgIA0KICAgDQoNCiBFbmhhbmNlZE1hcA0KYGBgDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=